﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using NetSurveillance.WebApp.DataServices.Models;
using ServiceStack.OrmLite;

namespace NetSurveillance.WebApp.DataServices.Implementations
{
    public class CaseService : BaseService<Case>
    {
        public CaseService(string connStr, IOrmLiteDialectProvider provider = null) : base(connStr, provider)
        {
        }

        public override IEnumerable<Case> GetAllModels(bool ignoreDeleted = false, System.Linq.Expressions.Expression<System.Func<Case, bool>> predicate = null)
        {
            var cases = base.GetAllModels(ignoreDeleted, predicate);
            var allModels = cases as List<Case> ?? cases.ToList();
            if (allModels.Count > 0)
            {
                using (var db = DbFactory.OpenDbConnection())
                {
                    var createdUserIds = allModels.Select(p => p.CreateUserId);
                    var users = db.Ids<User>(createdUserIds);
                    foreach (var user in users)
                    {
                        foreach (var caseEntry in cases.Where(caseEntry => caseEntry.CreateUserId == user.Id))
                        {
                            caseEntry.CreatedUser = user;
                        }
                    }
                }
            }
            return allModels;
        }

        public override ServiceResult Delete(long id)
        {
            using (var db = DbFactory.OpenDbConnection())
            {
                using (var trans = db.OpenTransaction(IsolationLevel.ReadCommitted))
                {
                    var casePmsList = db.Select<CasePermission>(p => p.CaseId == id && p.StatusToken != 0);
                    casePmsList.ForEach(p => p.StatusToken = 0);
                    db.SaveAll(casePmsList);
                    var caseEntry = db.Id<Case>(id);
                    caseEntry.StatusToken = 0;
                    db.Save(caseEntry);
                    trans.Commit();
                }
            }
            return ServiceResult.SuccessResult;
        }

        public IEnumerable<Case> GetCasesByCreatedUser(long userId)
        {
            using(var db = DbFactory.OpenDbConnection())
            {
                var cases = db.Select<Case>(p => p.StatusToken != 0 && p.CreateUserId == userId);
                if(cases.Count > 0)
                {
                    long craetedUserId = cases[0].CreateUserId;
                    var user = db.Id<User>(craetedUserId);
                    cases.ForEach(p => p.CreatedUser = user);
                }
                return cases;
            }
        }

        public ServiceResult SaveCasePermission(IEnumerable<CasePermission> casePmsList)
        {
            using (var db = DbFactory.OpenDbConnection())
            {
                using (var trans = db.OpenTransaction())
                {
                    try
                    {
                        foreach (var casePms in casePmsList)
                        {
                            var casePmsInDb =
                                db.SingleOrDefault<CasePermission>("\"CaseId\"={0} and \"UserId\"={1}".Params(casePms.CaseId, casePms.UserId));
                            if (casePmsInDb == null)
                                db.Insert(casePms);
                            else
                            {
                                casePmsInDb.StatusToken = 1;
                                casePmsInDb.Permission = casePms.Permission;
                                db.Update(casePmsInDb);
                            }
                        }
                    }
                    catch(Exception ex)
                    {
                        //todo:log the save exception
                        trans.Rollback();
                        return new ServiceResult {ExecutedSuccess = false, Message = ex.Message};
                    }
                    trans.Commit();
                }
                return ServiceResult.SuccessResult;
            }
        }

        public IEnumerable<CasePermission> GetCasePermissions(long caseId)
        {
            using (var db = DbFactory.OpenDbConnection())
            {
                var users = db.Select<User>(p => p.StatusToken != 0);
                var caseEntry = db.Id<Case>(caseId);
                var casePmses =
                    users.Where(p => p.Id != caseEntry.CreateUserId).Select(p => new CasePermission
                        {
                            UserId = p.Id,
                            CaseId = caseId,
                            User = p,
                            Case = caseEntry
                        }).ToList();
                var currentPmsList = db.Select<CasePermission>(p => p.StatusToken != 0 && p.CaseId == caseId);
                foreach (var casePms in casePmses)
                {
                    var pms = currentPmsList.FirstOrDefault(p => p.UserId == casePms.UserId);
                    if (pms == null) continue;
                    casePms.Id = pms.Id;
                    casePms.Permission = pms.Permission;
                }
                return casePmses;
            }
        }
 
        public Case GetRunningCase()
        {
            using (var db = DbFactory.OpenDbConnection())
            {
                var runningTask = db.Select<Task>(p => p.TaskStatus == TaskStatusType.Running ||
                                                       p.TaskStatus == TaskStatusType.Suspend).FirstOrDefault();
                if (runningTask == null)
                    return null;
                var runningCase = db.Id<Case>(runningTask.CaseId);
                return runningCase;
            }
        }
    }
}